﻿// <copyright file="PropertiesHeader.cs" company="Sinclair Community College">
// Copyright 2010 Sinclair Community College
// </copyright>
// <originalAuthor>Patrick S. Seymour (patrick.seymour@gmail.com)</originalAuthor>

namespace SinclairCC.AppV
{
    using System;
    using System.Diagnostics.CodeAnalysis;

    /// <summary>
    /// This class represents the properties header section in an App-V SFT/DSFT file.
    /// </summary>
    /// <remarks>
    /// The properties section of the SFT file stores basic package properties.
    /// </remarks>
    public class PropertiesHeader : HeaderMetadataSection
    {
        // TODO: Provide a way to check the validity of the bitrate field.

        /// <summary>
        /// This field is reserved and should be initialized to 0x0000E000 (56K).
        /// </summary>
        /// <remarks>
        /// Some older SFT files may store 0x00020000 (128K) in this field.
        /// </remarks>
        private int bitrate;

        /// <summary>
        /// This field is reserved and is initialized to all zeroes.
        /// </summary>
        [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Justification = "This field is marked as reserved in the App-V File Format Specification.")]
        private byte[] reserved1;

        // TODO: Provide a way to check the validity of the streamId field.

        /// <summary>
        /// This must have the value 0x00000001.
        /// </summary>
        private int streamId;

        /// <summary>
        /// This field stores the compression type as a numeric value.
        /// </summary>
        /// <remarks>When this field is initialized to any of the compression types defining
        /// effective compression, all the sections marked as being compressible need to be
        /// compressed. Note that the compression type must be uniform throughout the SFT file.</remarks>
        private CompressionMethod compressionType;

        // TODO: Provide a way to check the validity of the packageBlockSize value.

        /// <summary>
        /// This field stores the data block size used in the package.
        /// </summary>
        /// <remarks>
        /// No actual data block stored later in the file is expected to be less or more
        /// than this value unless it is either a file that is a size less than the block
        /// size or is the last block from multiple blocks belonging to a larger file.
        /// Currently two officially supported values for the block size are the default
        /// 32,768 (0x00008000) bytes and 65,536 (0x00010000) bytes.
        /// </remarks>
        private int packageBlockSize;

        /// <summary>
        /// This field is reserved and is initialized to all zeroes.
        /// </summary>
        [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Justification = "This field is marked as reserved in the App-V File Format Specification.")]
        private byte[] reserved2;

        /// <summary>
        /// Initializes a new instance of the PropertiesHeader class.
        /// </summary>
        /// <param name="fileReader">
        /// A binary file reader that points to the SFT file.
        /// </param>
        public PropertiesHeader(System.IO.BinaryReader fileReader)
            : base(fileReader)
        {
        }

        /// <summary>
        /// Gets the bitrate for this package.
        /// </summary>
        /// <remarks>
        /// This field is reserved and should be initialized to 0x0000E000 (56K).
        /// Some older SFT files may store 0x00020000 in this field.
        /// </remarks>
        public int Bitrate
        {
            get
            {
                this.ReadSection();
                return this.bitrate;
            }
        }

        /// <summary>
        /// Gets the stream ID, whatever that is.
        /// </summary>
        /// <remarks>
        /// This must have the value 0x00000001.
        /// </remarks>
        public int StreamID
        {
            get
            {
                this.ReadSection();
                return this.streamId;
            }
        }

        /// <summary>
        /// Gets a value indicating the compression method used in the SFT file.
        /// </summary>
        /// <remarks>
        /// Once a compression method is chosen, it must be applied to all compressible sections.
        /// </remarks>
        public CompressionMethod CompressionType
        {
            get
            {
                this.ReadSection();
                return this.compressionType;
            }
        }

        /// <summary>
        /// Gets the data block size used in the package.
        /// </summary>
        public int PackageBlockSize
        {
            get
            {
                this.ReadSection();
                return this.packageBlockSize;
            }
        }

        /// <summary>
        /// Reads the actual data for this section from the file.
        /// </summary>
        protected override void ReadSection()
        {
            if (this.SectionHasBeenRead)
            {
                return;
            }

            // Seek to the start of the data area for this section.
            long currentPosition = FileReader.BaseStream.Position;
            FileReader.BaseStream.Seek(this.StartPositionInFile + CommonSectionHeader.HeaderSize, System.IO.SeekOrigin.Begin);

            // Read the properties from the file.
            this.bitrate = FileReader.ReadInt32();
            this.reserved1 = FileReader.ReadBytes(4);
            this.streamId = FileReader.ReadInt32();

            int compressionFlag = FileReader.ReadInt32();
            if (Enum.IsDefined(typeof(CompressionMethod), compressionFlag))
            {
                this.compressionType = (CompressionMethod)compressionFlag;
            }
            else
            {
                this.compressionType = CompressionMethod.None;
            }

            this.packageBlockSize = FileReader.ReadInt32();
            this.reserved2 = FileReader.ReadBytes(4);

            this.SectionHasBeenRead = true;
            FileReader.BaseStream.Seek(currentPosition, System.IO.SeekOrigin.Begin);
        }
    }
}
